// defineProperty
// 首先Vue2当中通过observer对数据状态（data）进行数据变化的观察，一旦数据发生变化，会进行消息的发布来通知更改数据对应的订阅者。
// Vue2会对模块进行解析，在解析的过程序当中会对与数据产生绑定的DOM进行newWatch生成订阅者处理，并将订阅者对与其数据产生绑定。一旦数据变化，对应的订阅者会对DOM进行对应的操作。
// observe:负责对数据进行观察，一旦数据发生变化会通过该数据对应的订阅者
// compile:负责对模板进行解析。解析过程中可以对事件，指令进行功能的追加，负责增加订阅者。
// Watcher:创建订阅者。
function Vue(config={}){
	// beforeCreate()
	const {el,data={},methods={}} = config;
	this.$data = data;
	this.$binds = {};// {str:[订阅者1，订阅者2，订阅者3]}
	for(let key in methods){
		this[key] = methods[key];
	}
	// 对数据进行侦听（观察）
	this.observe();
	this.$mount(el);
	// created();
}
Object.assign(Vue.prototype,{
	$mount(el){
		this.$el = el;
		if(typeof el === "string"){
			this.$el = document.querySelector(el);
		}
		if(this.$el){
			this.compile(this.$el);
		}
	},
	observe(){
		for(let key in this.$data){
			this.$binds[key] = [];
			Object.defineProperty(this,key,{
				get(){
					return this.$data[key];
				},
				set(v){
					this.$data[key] = v;
					// 发布消息给订阅者
					this.$binds[key].forEach(watcher=>watcher.update(v))
				}
			})
		}
	},
	// 解析模板
	compile(nodes){
		for(let i=0;i<nodes.children.length;i++){
			// 获取节点
			const node = nodes.children[i];
			this.compile(node);
			// 判断有没有使用指令v-model
			if(node.hasAttribute("v-model")){
				// 1- 增加了input事件
				node.addEventListener("input",function(e){
					this[value] = e.target.value;
				}.bind(this))
				// data中的属性名
				const value = node.getAttribute("v-model");
				// 2- 绑定了数据
				node.value = this[value];
				// 生成订阅者，负责更新node.value属性值
				this.$binds[value].push(new Watcher(node,"value"))
			}
			// 判断node是否拥有指令v-html
			if(node.hasAttribute("v-html")){
				const value = node.getAttribute("v-html");
				node.innerHTML = this[value];
				// 生成订阅者，负责更新node.innerHTML
				this.$binds[value].push(new Watcher(node,"innerHTML"))
			}
			// 判断node是否拥有指令v-text
			if(node.hasAttribute("v-text")){
				const value = node.getAttribute("v-text");
				node.innerText = this[value];
				// 生成订阅者，负责更新node.innerText
				this.$binds[value].push(new Watcher(node,"innerText"))
			}
			if(node.hasAttribute("@click")){
				node.addEventListener("click",(e)=>{
					const value = node.getAttribute("@click");
					this[value](e);
				})
			}
		}
	}
})
function Watcher(node,prop){
	this.node = node;
	this.prop = prop;
}
Watcher.prototype.update = function(v){
	this.node[this.prop] = v;
}
export default Vue;